package cn.falcon.fmobi.console.controller;

import cn.falcon.fmobi.admin.dao.dao.model.ResultSetList;
import cn.falcon.fmobi.biz.common.Constant;
import cn.falcon.fmobi.biz.exception.AdvertiserValidateException;
import cn.falcon.fmobi.biz.exception.CampaignValidateException;
import cn.falcon.fmobi.biz.exception.ValidateException;
import cn.falcon.fmobi.biz.service.AdvertiserPlatformAuditService;
import cn.falcon.fmobi.biz.service.CommonService;
import cn.falcon.fmobi.biz.service.FmobiCampaignService;
import cn.falcon.fmobi.biz.service.dmp.RptGdtStrategyCreativeService;
import cn.falcon.fmobi.dao.model.CampaignListModel;
import cn.falcon.fmobi.console.common.RestfulJsonModelAndView;
import cn.falcon.fmobi.console.common.Result;
import cn.falcon.fmobi.console.constant.ParamConstant;
import cn.falcon.fmobi.console.constant.UrlConstant;
import cn.falcon.fmobi.console.exception.CallBackException;
import cn.falcon.fmobi.console.exception.ParamValidateException;
import cn.falcon.fmobi.console.requestparam.CampaignQueryParam;
import cn.falcon.fmobi.dao.enumration.AuditStatus;
import cn.falcon.fmobi.dao.interceptor.PageParameter;
import cn.falcon.fmobi.dao.po.AdvertiserPlatformAudit;
import cn.falcon.fmobi.dao.po.Campaign;
import cn.falcon.fmobi.dao.util.DataUtils;
import cn.falcon.fmobi.dao.util.DateUtil;
import cn.falcon.fmobi.dao.util.MathUtil;
import cn.falcon.marketing.api.enumeration.FundType;
import cn.falcon.marketing.api.enumeration.RealtimeCostType;
import cn.falcon.marketing.api.model.Po;
import cn.falcon.marketing.api.model.fund.FundsStructResult;
import cn.falcon.marketing.api.model.fund.RealtimeCost;
import cn.falcon.marketing.api.model.fund.RealtimeCostStructResult;
import cn.falcon.marketing.api.service.fund.IFundService;
import cn.falcon.marketing.api.util.JsonUtil;
import cn.falcon.marketing.api.util.ValidateUtil;
import com.sun.xml.internal.rngom.digested.DDataPattern;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 订单模块
 *
 * @author yujuan.zhang
 * @from 2017-10-15
 * @since V1.0
 */
@Controller
@RequestMapping(UrlConstant.CAMPAIGN_URL)
public class CampaignCtrl extends BaseCtrl {

    private static Logger logger = LoggerFactory.getLogger(CampaignCtrl.class);

    @Autowired
    private FmobiCampaignService fmobiCampaignService;

    @Autowired
    private RptGdtStrategyCreativeService rptGdtStrategyCreativeService;

    @Autowired
    private AdvertiserPlatformAuditService advertiserPlatformAuditService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private IFundService fundService;

    /**
     * 新建订单(只有广告主权限)
     *
     * @param campaign 订单参数列表
     * @return
     * @throws UnsupportedEncodingException
     * @throws ParamValidateException
     */
    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView addCampaign(@RequestBody Campaign campaign, HttpSession session)
        throws UnsupportedEncodingException, ParamValidateException {

        // 广告主权限 设置订单所属广告主id
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 权限验证 只有广告主权限可以新建订单
        if (null == advertiserId) {
            throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_NOT_AUTH);
        }
        // 设置广告主id
        if (null != advertiserId && null == campaign.getAdvertiserId()) {
            campaign.setAdvertiserId(advertiserId);
        }

        // 基础参数验证
        this.validateCampaignParam(campaign);
        // 平台id验证
        // 1. 广告主审核是否通过
        AdvertiserPlatformAudit advertiserPlatformAudit = advertiserPlatformAuditService
            .selectAdvertiserPlatformAuditByPlatformIdAndAdvertiserId(Constant.PLATFORM_ID_TENCENT,
                campaign.getAdvertiserId());
        if (null == advertiserPlatformAudit || !new Integer(AuditStatus.AUDIT_STATUS_SUCCESS.getValue())
            .equals(advertiserPlatformAudit.getAuditStatus())) {
            throw new CallBackException(AdvertiserValidateException.ErrorCode.ADVERTISER_AUDIT_NOT_SUCCESS.getValue(),
                AdvertiserValidateException.ErrorCode.ADVERTISER_AUDIT_NOT_SUCCESS.getDesc());
        }
        // 2. 平台是否被占用
        int count = fmobiCampaignService
            .getCampaignCountByAdvertiserIdAndPlatformId(campaign.getAdvertiserId(), Constant.PLATFORM_ID_TENCENT);
        if (count > 0) {
            throw new CallBackException(CampaignValidateException.ErrorCode.CAMPAIGN_PLATFORM_NOT_ENABLE.getValue(), CampaignValidateException.ErrorCode.CAMPAIGN_PLATFORM_NOT_ENABLE.getDesc());
        }

        // 获取溢价费率
        BigDecimal rate = readUserRates(session);
        logger.info("获取到的溢价费率为:[{}]", rate);
        // 获取用户id
        Integer userId = getCurrentUser().getId();

        // 腾讯社交平台 预算和日限额范围验证
        if (campaign.getPlatformId().equals(Constant.PLATFORM_ID_TENCENT)) {
            // 订单预算范围验证
            this.validateBudgetAmountChangeRange(0, campaign.getBudget(), rate);
            // 日限额范围验证
            this.validateDayBudgetAmountRange(campaign.getDayBudget(), rate);
        }

        // 查询广告主账户余额
        BigDecimal balanceCash = fmobiCampaignService.getAdvertiserBalanceCash(campaign.getAdvertiserId());
        logger.info("广告主[{}]账户余额为[{}]元(数据库原始值)", campaign.getAdvertiserId(), balanceCash);
        // 验证广告主账户余额是否充足
        this.validateAdvertiserBalanceCash(balanceCash, campaign.getBudget(), rate);

        // 设置订单预算的真实值
        campaign.setBudget(MathUtil.mulBigDecimal(campaign.getBudget(), rate));
        // 设置订单日限额的真实值
        campaign.setDayBudget(MathUtil.mulBigDecimal(campaign.getDayBudget(), rate));
        // 新建订单
        fmobiCampaignService.addCampaign(campaign, userId);
        return RestfulJsonModelAndView.buildJsonModelAndView();

    }

    /**
     * 查询订单信息(只有广告主和代理商权限可以查看)
     *
     * @param id 订单id
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "/{id}")
    public ModelAndView getCampaignDetailInfo(@PathVariable Integer id, HttpSession session) {
        try {
            // 权限验证
            Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
            Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;
            if (null == advertiserId && null == agentId) {
                throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_NOT_AUTH);
            }
            // 查询订单信息
            Campaign campaignFromDB = fmobiCampaignService.getCampaign(id);
            if (null == campaignFromDB) {
                throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_NOT_FOUND);
            }
            // 权限验证
            if ((null != advertiserId && !advertiserId.equals(campaignFromDB.getAdvertiserId())) ||
                (null != agentId && !customerService.agentExistAdvertiser(agentId, campaignFromDB.getAdvertiserId()))) {
                throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_NOT_AUTH);
            }
            // 获取溢价费率
            BigDecimal rate = readUserRates(session);
            logger.info("获取到的溢价费率为:[{}]", rate);
            // 预算 溢价处理
            campaignFromDB.setBudget(MathUtil.divBigDecimal(campaignFromDB.getBudget(), rate));
            // 日限额 溢价处理
            campaignFromDB.setDayBudget(MathUtil.divBigDecimal(campaignFromDB.getDayBudget(), rate));
            return RestfulJsonModelAndView.buildJsonModelAndView(campaignFromDB);
        } catch (ValidateException ex) {
            throw new CallBackException(ex.getCode().getValue(), ex.getCode().getDesc());
        }
    }

    /***
     * 编辑订单(只有广告主权限可以操作)
     *
     * @param campaign 订单参数列表
     * @return
     * @throws UnsupportedEncodingException
     * @throws ParamValidateException
     */
    @RequestMapping(method = RequestMethod.PUT)
    public ModelAndView updateCampaign(@RequestBody Campaign campaign, HttpSession session)
        throws UnsupportedEncodingException, ParamValidateException {
        // 广告主权限
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 权限验证
        if (null == advertiserId) {
            throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_NOT_AUTH);
        }
        // 设置订单所属广告主id
        if (null != advertiserId && null == campaign.getAdvertiserId()) {
            campaign.setAdvertiserId(advertiserId);
        }

        // 参数验证
        if (0 == campaign.getId()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "id", "Result.err.miss.parameter");
        }
        this.validateCampaignParam(campaign);

        // 查询订单信息
        Campaign campaignFromDB = fmobiCampaignService.getCampaign(campaign.getId());
        if (null == campaignFromDB) {
            logger.error("订单不存在：{}", JsonUtil.toJson(campaign));
            throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_NOT_FOUND);
        }
        logger.info("查询到的订单信息(数据库原始值)：[{}]", JsonUtil.toJson(campaignFromDB));

        // 广告主不可修改
        if (!campaign.getAdvertiserId().equals(campaignFromDB.getAdvertiserId())) {
            logger.error("编辑订单时，所属广告主不可修改");
            throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_ADVERTISER_CAN_NOT_CHANGE);
        }
        // 平台不可修改
        if (!campaign.getPlatformId().equals(campaignFromDB.getPlatformId())) {
            logger.error("编辑订单时，所属平台不可修改");
            throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_PLATFORM_CAN_NOT_CHANGE);
        }

        // 获取溢价费率
        BigDecimal rate = readUserRates(session);
        logger.info("获取到的溢价费率为:[{}]", rate);
        // 获取用户id
        Integer userId = getCurrentUser().getId();

        // 对数据库中查询出的值进行溢价处理
        BigDecimal budgetFromDB = MathUtil.divBigDecimal(campaignFromDB.getBudget(), rate);
        BigDecimal dayBudgetFromDB = MathUtil.divBigDecimal(campaignFromDB.getDayBudget(), rate);

        // 预算修改幅度
        BigDecimal budgetChangeAmount = campaign.getBudget().subtract(budgetFromDB).abs();
        // 日限额修改幅度
        BigDecimal dayBudgetChangeAmount = campaign.getDayBudget().subtract(dayBudgetFromDB).abs();
        // 从广告主表查询广告主账户余额
        BigDecimal balanceCash = fmobiCampaignService.getAdvertiserBalanceCash(campaign.getAdvertiserId());

        // 腾讯社交平台
        if (campaign.getPlatformId().equals(Constant.PLATFORM_ID_TENCENT)) {
            // 查询广点通广告主id
            AdvertiserPlatformAudit advertiserPlatformAudit = advertiserPlatformAuditService
                .selectAdvertiserPlatformAuditByPlatformIdAndAdvertiserId(Constant.PLATFORM_ID_TENCENT,
                    campaign.getAdvertiserId());
            Integer tencentAdvertiserId = advertiserPlatformAudit.getPlatformAdvertiserId();
            // 查询腾讯社交广告主账户余额
            BigDecimal tencentAdvertiserBalanceCash = this.getTencentAdvertiserBalanceCash(tencentAdvertiserId);

            // 预算或者日限额有修改 需要验证广告主审核状态
            if (0 != campaign.getBudget().compareTo(budgetFromDB) ||
                0 != campaign.getDayBudget().compareTo(dayBudgetFromDB)) {
                // 预算修改 关联到 腾讯社交广告主划账 需要腾讯社交广告主审核通过
                // 日限额修改 关联到 腾讯社交广告主日限额修改 需要腾讯社交广告主审核通过
                if (!new Integer(AuditStatus.AUDIT_STATUS_SUCCESS.getValue())
                    .equals(advertiserPlatformAudit.getAuditStatus())) {
                    throw new AdvertiserValidateException(
                        AdvertiserValidateException.ErrorCode.ADVERTISER_AUDIT_NOT_SUCCESS);
                }
            }

            // 1. 参数验证
            // 1.1 预算参数验证
            if (0 != campaign.getBudget().compareTo(budgetFromDB)) {
                // 预算修改幅度验证
                this.validateBudgetAmountChangeRange(1, budgetChangeAmount, rate);
                // 预算增加
                if (1 == campaign.getBudget().compareTo(budgetFromDB)) {
                    // 验证广告主账户余额是否充足
                    this.validateAdvertiserBalanceCash(balanceCash, budgetChangeAmount, rate);
                }
                // 预算减少
                if (-1 == campaign.getBudget().compareTo(budgetFromDB)) {
                    // 查询腾讯社交广告主账户余额是否充足
                    this.validateTencentAdvertiserBalanceCash(tencentAdvertiserBalanceCash, budgetChangeAmount, rate);
                }
            }

            // 1.2 日限额验证
            if (0 != campaign.getDayBudget().compareTo(dayBudgetFromDB)) {
                // 日限额范围验证
                this.validateDayBudgetAmountRange(campaign.getDayBudget(), rate);
                // 日限额修改幅度验证
                this.validateDayBudgetAmountChangeRange(tencentAdvertiserId, dayBudgetChangeAmount, rate);
            }
        }

        // 请求参数 预算 做溢价处理
        campaign.setBudget(MathUtil.mulBigDecimal(campaign.getBudget(), rate));
        // 请求参数 日限额 做溢价处理
        campaign.setDayBudget(MathUtil.mulBigDecimal(campaign.getDayBudget(), rate));
        // 编辑订单
        fmobiCampaignService.editCampaign(campaign, userId);
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 订单列表分页查询(只有广告主和代理商权限可以操作)
     *
     * @param campaignQueryParam 订单查询参数
     * @param session
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView getCampaignListByPage(CampaignQueryParam campaignQueryParam, HttpSession session)
        throws ParamValidateException {
        // 查询参数验证
        if (null == campaignQueryParam.getStartDate()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "startDate", "Result.err.miss.parameter");
        }
        if (null == campaignQueryParam.getEndDate()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "endDate", "Result.err.miss.parameter");
        }
        if (campaignQueryParam.getStartDate().after(campaignQueryParam.getEndDate())) {
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "startDate endDate",
                "Result.err.invalid.parameter");
        }

        // 权限
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;
        // 权限验证
        if (null == advertiserId && null == agentId) {
            throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_NOT_AUTH);
        }
        // 广告主权限时，查询参数中设置广告主id
        if (null != advertiserId) {
            campaignQueryParam.setAdvertiserId(advertiserId);
        }
        campaignQueryParam.setAgentId(agentId);

        // 分页参数
        PageParameter pageParameter = campaignQueryParam.getPageInfo();

        // 订单列表分页查询
        List<CampaignListModel> campaignList = fmobiCampaignService
            .getCampaignListByPage(campaignQueryParam.getSearchMap(), pageParameter);

        // 当列表不为空 并且 查询时间早于今天 查询数据报告
        if (!DataUtils.isNull(campaignList) && DateUtil.getStartTime(campaignQueryParam.getStartDate()).getTime() <=
            DateUtil.getStartTime(new Date()).getTime()) {
            // 订单id列表
            List<Integer> campaignIds = new ArrayList<>();
            for (CampaignListModel campaign: campaignList) {
                campaignIds.add(campaign.getId());
                // 查询总花费
                Double totalCost = rptGdtStrategyCreativeService.getTotalCostByCampaignId(campaign.getId());
                // 设置总花费
                campaign.setTotalCost(null == totalCost ? 0 : totalCost);
            }

            // 数据报告查询参数
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("startDate", campaignQueryParam.getStartDate());
            paramMap.put("endDate", campaignQueryParam.getEndDate());
            paramMap.put("campaignIds", campaignIds);

            campaignList = commonService.createRpt(paramMap, campaignList, readUserRates(session));
        } else {
            // 查询订单总花费
            for (CampaignListModel campaign: campaignList) {
                // 查询总花费
                Double totalCost = rptGdtStrategyCreativeService.getTotalCostByCampaignId(campaign.getId());
                // 设置总花费
                campaign.setTotalCost(null == totalCost ? 0 : MathUtil
                    .divBigDecimal(BigDecimal.valueOf(totalCost), readUserRates(session)).doubleValue());
            }
        }

        // 设置返回结果
        return RestfulJsonModelAndView
            .buildJsonModelAndView(new ResultSetList<>(pageParameter.getTotalCount(), campaignList));
    }

    /**************************************************************************************************/

    /**
     * 订单参数列表验证
     *
     * @param campaign 订单参数列表
     * @throws ParamValidateException
     * @throws UnsupportedEncodingException
     */
    private void validateCampaignParam(Campaign campaign) throws ParamValidateException, UnsupportedEncodingException {

        // 订单名称必填
        if (StringUtils.isEmpty(campaign.getName())) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "name", "Result.err.miss.parameter");
        }

        // 订单名称长度
        if (ValidateUtil.checkStrByteLengthMoreThan(campaign.getName(), ParamConstant.CAMPAIGN_NAME_LENGTH_MAX)) {
            throw new ParamValidateException(Result.ERR_INVALID_LENGTH, "name", "Result.err.invalid.length");
        }

        // 广告主必填
        if (null == campaign.getAdvertiserId()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "advertiserId", "Result.err.miss.parameter");
        }

        // 开始时间必填
        if (null == campaign.getStartTime()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "startTime", "Result.err.miss.parameter");
        }

        // 如果结束时间不为空，判断开始时间是否早于结束时间
        if (null != campaign.getEndTime() && campaign.getStartTime().after(campaign.getEndTime())) {
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "endTime", "Result.err.invalid.parameter");
        }

        // 备注长度验证
        if (!StringUtils.isEmpty(campaign.getDescription()) && ValidateUtil
            .checkStrByteLengthMoreThan(campaign.getDescription(), ParamConstant.CAMPAIGN_DESCRIPTION_LENGTH_MAX)) {
            throw new ParamValidateException(Result.ERR_INVALID_LENGTH, "description", "Result.err.invalid.length");
        }

        // 预算
        if (null == campaign.getBudget()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "budget", "Result.err.miss.parameter");
        }

        // 每日限额 必填
        if (null == campaign.getDayBudget() || BigDecimal.ZERO.equals(campaign.getDayBudget())) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "dayBudget", "Result.err.miss.parameter");
        }

        // 平台id必填
        if (null == campaign.getPlatformId()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "platformId", "Result.err.miss.parameter");
        }
    }

    /**
     * 预算修改幅度验证
     *
     * @param i                  0 代表订单新建时设置预算验证 1 代表订单编辑时预算修改幅度验证
     * @param budgetChangeAmount 订单预算修改幅度
     * @param rate               溢价费率
     */
    private void validateBudgetAmountChangeRange(int i, BigDecimal budgetChangeAmount, BigDecimal rate) {
        // 最小值向上取整 保留到十位
        // 首先四舍五入取整
        int minAmount = (BigDecimal.valueOf(ParamConstant.CAMPAIGN_BUDGET_MIN)
            .divide(rate, 0, BigDecimal.ROUND_HALF_UP)).intValue();
        minAmount = (int) (minAmount % 10 != 0 ? ((Math.floor(minAmount / 10) + 1) * 10) : minAmount);
        // 最大值向下取整 保留到万位
        // 首先四舍五入取整
        int maxAmount = (BigDecimal.valueOf(ParamConstant.CAMPAIGN_BUDGET_MAX)
            .divide(rate, 0, BigDecimal.ROUND_HALF_UP)).intValue();
        maxAmount = (int) (maxAmount % 10000 != 0 ? ((Math.floor(maxAmount / 10000)) * 10000) : maxAmount);

        if (1 == BigDecimal.valueOf(minAmount).compareTo(budgetChangeAmount) ||
            -1 == BigDecimal.valueOf(maxAmount).compareTo(budgetChangeAmount)) {

            // 订单预算范围验证
            if (i == 0) {
                throw new CampaignValidateException(minAmount + "", maxAmount + "",
                    CampaignValidateException.ErrorCode.CAMPAIGN_BUDGET_AMOUNT);
            }

            // 订单预算修改幅度验证
            if (i == 1) {
                throw new CampaignValidateException(minAmount + "", maxAmount + "",
                    CampaignValidateException.ErrorCode.CAMPAIGN_BUDGET_AMOUNT_UPDATE_RANGE);
            }
        }
    }

    /**
     * 订单每日限额范围验证
     *
     * @param dayBudget 每日限额
     * @param rate      溢价费率
     */
    private void validateDayBudgetAmountRange(BigDecimal dayBudget, BigDecimal rate) {
        // 最小值向上取整 保留到十位
        // 首先四舍五入取整
        int minAmount = (BigDecimal.valueOf(ParamConstant.CAMPAIGN_DAY_BUDGET_MIN)
            .divide(rate, 0, BigDecimal.ROUND_HALF_UP)).intValue();
        minAmount = (int) (minAmount % 10 != 0 ? ((Math.floor(minAmount / 10) + 1) * 10) : minAmount);
        // 最大值向下取整 保留到万位
        // 首先四舍五入取整
        int maxAmount = (BigDecimal.valueOf(ParamConstant.CAMPAIGN_DAY_BUDGET_MAX)
            .divide(rate, 0, BigDecimal.ROUND_HALF_UP)).intValue();
        maxAmount = (int) (maxAmount % 10000 != 0 ? ((Math.floor(maxAmount / 10000)) * 10000) : maxAmount);

        if (1 == BigDecimal.valueOf(minAmount).compareTo(dayBudget) ||
            -1 == BigDecimal.valueOf(maxAmount).compareTo(dayBudget)) {
            throw new CampaignValidateException(minAmount + "", maxAmount + "",
                CampaignValidateException.ErrorCode.CAMPAIGN_DAY_BUDGET_AMOUNT);
        }
    }

    /**
     * 每日限额修改幅度验证
     *
     * @param tencentAdvertiserId   腾讯社交广告主id
     * @param dayBudgetChangeAmount 每日限额修改幅度
     * @param rate                  溢价费率
     */
    private void validateDayBudgetAmountChangeRange(Integer tencentAdvertiserId, BigDecimal dayBudgetChangeAmount,
        BigDecimal rate) {
        // 查询腾讯社交平台的广告主的今日消耗
        RealtimeCost realtimeCost = new RealtimeCost();
        realtimeCost.setAccount_id(tencentAdvertiserId);
        realtimeCost.setLevel(RealtimeCostType.ADVERTISER.name());
        realtimeCost.setDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        List<RealtimeCostStructResult> realtimeCostStructResults = fundService.realtimeCostGet(realtimeCost, false);
        // 单位为分
        Integer cost = realtimeCostStructResults.get(0).getCost();
        logger.info("广告主[{}]的今日消耗为[{}]", tencentAdvertiserId, cost);

        // 修改幅度不得小于今日消耗加上50元
        // 注意 运算优先级 cost先除以100转化为元 然后加上50元
        BigDecimal min = BigDecimal.valueOf(50).add(BigDecimal.valueOf(cost).divide(BigDecimal.valueOf(100)));
        // 溢价处理 向上取整保留到十位
        int minDayBudget = min.divide(rate, 0, BigDecimal.ROUND_HALF_UP).intValue();
        minDayBudget = (int) (minDayBudget % 10 != 0 ? ((Math.floor(minDayBudget / 10) + 1) * 10) : minDayBudget);

        if (1 == BigDecimal.valueOf(minDayBudget).compareTo(dayBudgetChangeAmount)) {
            logger.error("订单每日限额修改幅度不得小于[{}]元", minDayBudget);
            throw new CampaignValidateException(minDayBudget + "",
                CampaignValidateException.ErrorCode.CAMPAIGN_DAY_BUDGET_AMOUNT_UPDATE_RANGE);
        }
    }

    /***
     * 验证广告主账户余额是否充足
     *
     * @param balanceCash           广告主账户余额
     * @param budgetAmountChange    新建订单时订单的预算值 或者 编辑订单时订单预算的增加值
     * @param rate                  溢价费率
     */
    private void validateAdvertiserBalanceCash(BigDecimal balanceCash, BigDecimal budgetAmountChange, BigDecimal rate) {
        if ((null == balanceCash || BigDecimal.ZERO.compareTo(balanceCash) == 0) ||
            (-1 == MathUtil.divBigDecimal(balanceCash, rate).compareTo(budgetAmountChange))) {
            logger.error("广告主账户余额balanceCash[{}]不足", balanceCash);
            throw new AdvertiserValidateException(AdvertiserValidateException.ErrorCode.ADVERTISER_AMOUNT);
        }
    }

    /**
     * 查询腾讯社交广告主账户余额
     *
     * @param tencentAdvertiserId 腾讯社交广告主id
     * @return
     */
    private BigDecimal getTencentAdvertiserBalanceCash(Integer tencentAdvertiserId) {
        Po po = new Po();
        po.setAccount_id(tencentAdvertiserId);
        List<FundsStructResult> fundResult = fundService.fundsGet(po, true);
        BigDecimal balanceCash = null;
        for (FundsStructResult fund : fundResult) {
            if (FundType.GENERAL_CASH.equals(fund.getFund_type())) {
                // 分转化为元
                balanceCash = new BigDecimal(fund.getBalance()).divide(new BigDecimal(100));
            }
        }
        logger.info("腾讯社交广告主[{}]账户余额为[{}]", tencentAdvertiserId, balanceCash);
        return balanceCash;
    }

    /**
     * 验证腾讯社交广告主账户余额是否充足
     *
     * @param tencentAdvertiserBalanceCash 腾讯社交广告主id
     * @param budgetChangeAmount           编辑订单时订单预算的减少值
     * @param rate                         溢价费率
     */
    public void validateTencentAdvertiserBalanceCash(BigDecimal tencentAdvertiserBalanceCash,
        BigDecimal budgetChangeAmount, BigDecimal rate) {
        // 腾讯社交广告主账户余额不足
        if ((null == tencentAdvertiserBalanceCash || BigDecimal.ZERO.compareTo(tencentAdvertiserBalanceCash) == 0) ||
            (-1 == MathUtil.divBigDecimal(tencentAdvertiserBalanceCash, rate).compareTo(budgetChangeAmount))) {
            logger.error("腾讯社交广告主账户余额为[{}]元，账户余额不足！", tencentAdvertiserBalanceCash);
            throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_BUDGET_REMAIN_NOT_ENOUGH);
        }
    }

}
